﻿using Microsoft.TeamFoundation.VersionControl.Client;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tfs_analyzer.BaseValidators;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Collections.ObjectModel;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Framework.Common;
using Microsoft.TeamFoundation.Framework.Client;
using Tfs_analyzer;
using System.Diagnostics;
using Microsoft.TeamFoundation.Server;

namespace Tfs_analyzer
{
    class ChangesetReportGenerator
    {
        private List<IChangesetValidator> m_validators;

        public ChangesetReportGenerator()
        {
          m_validators = new List<IChangesetValidator>();
          m_validators.Add(new AttachedWorkItemsValidator());
          m_validators.Add(new ChangesetCommentValidator());
          m_validators.Add(new ChangesetPerDayCountValidator());
        }

        public ValidationSummary GenerateReportFor(TfsConfigurationServer tfs, CatalogNode collectionNode, string project, List<string> project_group, TimeSpan period)
          {
          ValidationSummary validation = new ValidationSummary();
          validation.period = period;
          validation.project = project;
          
          List<Identity> members = new List<Identity>();

          foreach (var groups in project_group)
            {
            var found = GetMembersOfGroup(collectionNode, tfs, project, groups);
            if(found != null)
              members.AddRange(found);
            }
            

          if (members.Count == 0)
            {
            Console.WriteLine("There is no any members or group " + project + " group name:" + project_group);
            return validation;
            }

          var serv = GetVersionControlServer(collectionNode, tfs);
          IEnumerable res = serv.QueryHistory(project, LatestVersionSpec.Instance, 0, RecursionType.Full, null, new DateVersionSpec(DateTime.Now - period), LatestVersionSpec.Instance, Int32.MaxValue, false, false);

          foreach (Changeset changeset in res)
            {
            var member = members.FirstOrDefault(o => (o.DisplayName.Contains(changeset.OwnerDisplayName.ToString())));
            if (member!= null)
              validation.m_validation_info.Add(changeset);
            }
            

          return validation; 
          }

      static string FindSidOfGroup(CatalogNode collectionNode, TfsConfigurationServer tfs, string project, string group_name_to_lookup)
        {
        ServiceDefinition tpcServiceDefinition = collectionNode.Resource.ServiceReferences["Location"];
        ILocationService configLocationService = tfs.GetService<ILocationService>();
        Uri tpcUri = new Uri(configLocationService.LocationForCurrentConnection(tpcServiceDefinition));

        var tfs_2 = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(tpcUri);
        var vsStore = tfs_2.GetService<VersionControlServer>();

        var proj = vsStore.TryGetTeamProject(project.Replace("$/", ""));
        var security_Service = tfs_2.GetService<IGroupSecurityService>();
        var groupList = security_Service.ListApplicationGroups(proj.ArtifactUri.ToString());

        Queue<Identity> que = new Queue<Identity>(groupList);

        while (que.Count > 0)
          {
          var found_group = que.FirstOrDefault(o => (o.DisplayName.ToUpper().Contains(group_name_to_lookup)));

          if (found_group != null)
            return found_group.Sid;

          Identity sub_gr = null;
          do
            {
            sub_gr = que.Peek();
            que.Dequeue();
            } while (sub_gr.Sid.Length == 0);

          if (sub_gr == null)
            continue;

          Identity sids = security_Service.ReadIdentity(SearchFactor.Sid, sub_gr.Sid, QueryMembership.Expanded);
          if (sids.Members.Length == 0)
            continue;

          Console.WriteLine("Looking in " + sids.DisplayName + " for " + group_name_to_lookup);

          List<Identity> contributors = security_Service.ReadIdentities(SearchFactor.Sid, sids.Members, QueryMembership.Expanded).ToList();
          foreach (var i in contributors)
            que.Enqueue(i);
          }

        return null;
        }

      static List<Identity> GetMembersOfGroup(CatalogNode collectionNode, TfsConfigurationServer tfs, string project, string group_name_to_lookup)
        {
        ServiceDefinition tpcServiceDefinition = collectionNode.Resource.ServiceReferences["Location"];
        ILocationService configLocationService = tfs.GetService<ILocationService>();
        Uri tpcUri = new Uri(configLocationService.LocationForCurrentConnection(tpcServiceDefinition));

        var tfs_2 = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(tpcUri);
        var vsStore = tfs_2.GetService<VersionControlServer>();

        var proj = vsStore.TryGetTeamProject(project.Replace("$/", ""));
        var security_Service = tfs_2.GetService<IGroupSecurityService>();
        var groupList = security_Service.ListApplicationGroups(proj.ArtifactUri.ToString());

        var sid = FindSidOfGroup(collectionNode, tfs, project, group_name_to_lookup);

        if (sid.Length == 0)
          return null;

        Identity sids = security_Service.ReadIdentity(SearchFactor.Sid, sid, QueryMembership.Expanded);
        if (sids.Members.Length == 0)
          return null;

        return security_Service.ReadIdentities(SearchFactor.Sid, sids.Members, QueryMembership.Expanded).ToList();
        }

      static VersionControlServer GetVersionControlServer(CatalogNode collectionNode, TfsConfigurationServer tfs)
        {
        // Use the InstanceId property to get the team project collection
        Guid collectionId = new Guid(collectionNode.Resource.Properties["InstanceId"]);
        TfsTeamProjectCollection teamProjectCollection = tfs.GetTeamProjectCollection(collectionId);
        var serv = teamProjectCollection.GetService<VersionControlServer>();
        return serv;
        }
    }
}
